home

load libraries


### https://cran.r-project.org/web/packages/udpipe/vignettes/udpipe-usecase-postagging-lemmatisation.html
library(udpipe)
ud_model <- udpipe_download_model(language = "english")
library(tidyverse)
library(tidyr)
library(dplyr)
library(ggplot2)
library(ggrepel)
library(knitr)
library(tm)
library(quanteda)
library(lattice)
library(latticeExtra)
library(plotly)
library(pdp)
library(patchwork)

load the FW functions


### CODE DIRECTLY FROM: https://burtmonroe.github.io/TextAsDataCourse/Tutorials/TADA-FightinWords.nb.html#
fwgroups <- function(dtm, groups, pair = NULL, weights = rep(1,nrow(dtm)), k.prior = .1) {
  
  weights[is.na(weights)] <- 0
  
  weights <- weights/mean(weights)
  
  zero.doc <- rowSums(dtm)==0 | weights==0
  zero.term <- colSums(dtm[!zero.doc,])==0
  
  dtm.nz <- apply(dtm[!zero.doc,!zero.term],2,"*", weights[!zero.doc])
  
  g.prior <- tcrossprod(rowSums(dtm.nz),colSums(dtm.nz))/sum(dtm.nz)
  
  # 
  
  g.posterior <- as.matrix(dtm.nz + k.prior*g.prior)
  
  groups <- groups[!zero.doc]
  groups <- droplevels(groups)
  
  g.adtm <- as.matrix(aggregate(x=g.posterior,by=list(groups=groups),FUN=sum)[,-1])
  rownames(g.adtm) <- levels(groups)
  
  g.ladtm <- log(g.adtm)
  
  g.delta <- t(scale( t(scale(g.ladtm, center=T, scale=F)), center=T, scale=F))
  
  g.adtm_w <- -sweep(g.adtm,1,rowSums(g.adtm)) # terms not w spoken by k
  g.adtm_k <- -sweep(g.adtm,2,colSums(g.adtm)) # w spoken by groups other than k
  g.adtm_kw <- sum(g.adtm) - g.adtm_w - g.adtm_k - g.adtm # total terms not w or k 
  
  g.se <- sqrt(1/g.adtm + 1/g.adtm_w + 1/g.adtm_k + 1/g.adtm_kw)
  
  g.zeta <- g.delta/g.se
  
  g.counts <- as.matrix(aggregate(x=dtm.nz, by = list(groups=groups), FUN=sum)[,-1])
  
  if (!is.null(pair)) {
    pr.delta <- t(scale( t(scale(g.ladtm[pair,], center = T, scale =F)), center=T, scale=F))
    pr.adtm_w <- -sweep(g.adtm[pair,],1,rowSums(g.adtm[pair,]))
    pr.adtm_k <- -sweep(g.adtm[pair,],2,colSums(g.adtm[pair,])) # w spoken by groups other than k
    pr.adtm_kw <- sum(g.adtm[pair,]) - pr.adtm_w - pr.adtm_k - g.adtm[pair,] # total terms not w or k
    pr.se <- sqrt(1/g.adtm[pair,] + 1/pr.adtm_w + 1/pr.adtm_k + 1/pr.adtm_kw)
    pr.zeta <- pr.delta/pr.se
    
    return(list(zeta=pr.zeta[1,], delta=pr.delta[1,],se=pr.se[1,], counts = colSums(dtm.nz), acounts = colSums(g.adtm)))
  } else {
    return(list(zeta=g.zeta,delta=g.delta,se=g.se,counts=g.counts,acounts=g.adtm))
  }
}

############## FIGHTIN' WORDS PLOTTING FUNCTION

# helper function
makeTransparent<-function(someColor, alpha=100)
{
  newColor<-col2rgb(someColor)
  apply(newColor, 2, function(curcoldata){rgb(red=curcoldata[1], green=curcoldata[2],
                                              blue=curcoldata[3],alpha=alpha, maxColorValue=255)})
}

fw.ggplot.groups <- function(fw.ch, groups.use = as.factor(rownames(fw.ch$zeta)), max.words = 50, max.countrank = 400, colorpalette=rep("black",length(groups.use)), sizescale=2, title="Comparison of Terms by Groups", subtitle = "", caption = "Group-specific terms are ordered by Fightin' Words statistic (Monroe, et al. 2008)") {
  if (is.null(dim(fw.ch$zeta))) {## two-group fw object consists of vectors, not matrices
    zetarankmat <- cbind(rank(-fw.ch$zeta),rank(fw.ch$zeta))
    colnames(zetarankmat) <- groups.use
    countrank <- rank(-(fw.ch$counts))
  } else {
    zetarankmat <- apply(-fw.ch$zeta[groups.use,],1,rank)
    countrank <- rank(-colSums(fw.ch$counts))
  }
  wideplotmat <- as_tibble(cbind(zetarankmat,countrank=countrank))
  wideplotmat$term=names(countrank)
  #rankplot <- gather(wideplotmat, party, zetarank, 1:ncol(zetarankmat))
  rankplot <- gather(wideplotmat, groups.use, zetarank, 1:ncol(zetarankmat))
  rankplot$plotsize <- sizescale*(50/(rankplot$zetarank))^(1/4)
  rankplot <- rankplot[rankplot$zetarank < max.words + 1 & rankplot$countrank<max.countrank+1,]
  rankplot$groups.use <- factor(rankplot$groups.use,levels=groups.use)
  
  p <- ggplot(rankplot, aes((nrow(rankplot)-countrank)^1, -(zetarank^1), colour=groups.use)) + 
    geom_point(show.legend=F,size=sizescale/2) + 
    theme_classic() +
    theme(axis.ticks=element_blank(), axis.text=element_blank() ) +
    ylim(-max.words,40) +
    facet_grid(groups.use ~ .) +
    geom_text_repel(aes(label = term), size = rankplot$plotsize, point.padding=.05,
                    box.padding = unit(0.20, "lines"), show.legend=F) +
    scale_colour_manual(values = alpha(colorpalette, .7)) + 
#    labs(x="Terms used more frequently overall →", y="Terms used more frequently by group →",  title=title, subtitle=subtitle , caption = caption) 
    labs(x=paste("Terms used more frequently overall -->"), y=paste("Terms used more frequently by group -->"),  title=title, subtitle=subtitle , caption = caption) 
  
}

fw.keys <- function(fw.ch,n.keys=10) {
  n.groups <- nrow(fw.ch$zeta)
  keys <- matrix("",n.keys,n.groups)
  colnames(keys) <- rownames(fw.ch$zeta)
  
  for (g in 1:n.groups) {
    keys[,g] <- names(sort(fw.ch$zeta[g,],dec=T)[1:n.keys])
  }
  keys
}

Compare NYT 1994-2010: Before and After “extremist”

Load and clean the data


text_cleaner<-function(corpus){
  tempcorpus<-Corpus(VectorSource(corpus))
  tempcorpus<-tm_map(tempcorpus,
                    removePunctuation)
  tempcorpus<-tm_map(tempcorpus,
                    stripWhitespace)
  tempcorpus<-tm_map(tempcorpus,
                    removeNumbers)
  tempcorpus<-tm_map(tempcorpus,
                     removeWords, stopwords("english"))
  tempcorpus<-tm_map(tempcorpus, 
                    stemDocument)
  return(tempcorpus)
}

Calculate FW.

Get and show the top words per group by zeta.


fwkeys.extrem <- fw.keys(fw.extrem, n.keys=20)
cols <- rev(colnames(fwkeys.extrem))
fwkeys.extrem <- fwkeys.extrem[,cols]

##################################################################

kable(fwkeys.extrem)
Context.before Context.after
rightw group
mesopotamia view
homegrown element
sunni organ
islamic movement
paint hama
portray activ
jewish agenda
alqaida settler
yitzhak militia
evid caus
secur foreign
assassin respons
member by
minist foreignl
track oppos
iraq fring
belong posit
small led
monitor addit
NA

Plot: Before in Blue, After in Red


p.fw.extrem <- fw.ggplot.groups(fw.extrem,sizescale=4,max.words=200,
                                max.countrank=400,colorpalette=c("red","blue"),
                                 title = 'Comparison of Terms Before and After "Extremist"')
p.fw.extrem

Calculate Parts of speech by before and after

Calculate FW and keys


ud_model <- udpipe_load_model(ud_model$file_model)

txt <-as.character(extrem_NYT.dfm.long$context.text)

x_udp <- udpipe_annotate(ud_model, x = txt, doc_id = seq_along(txt))
x <- as.data.frame(x_udp)

x$doc_id <-as.integer(x$doc_id)

##################################################################

x_odd.before <- x[x$doc_id %% 2 == 1,]
x_even.after <-x[x$doc_id %% 2 == 0, ]

Bar Charts from Functions Above


UPOS_barchart(x_odd.before, x_even.after)

NOUNS_barchart(x_odd.before, x_even.after)

ADJ_barchart(x_odd.before, x_even.after)

RAKE_KW_barchart(x_odd.before, x_even.after)

PWI_barchart(x_odd.before, x_even.after)

POS_barchart(x_odd.before, x_even.after)

NA
NA

Cooccurences

Cooccurences (part 2)



Corrs <- function(df){
  df$id <- unique_identifier(df, fields = c("sentence_id", "doc_id"))
  dtm <- subset(df, upos %in% c("NOUN", "ADJ"))
  dtm <- document_term_frequencies(dtm, document = "id", term = "lemma")
  dtm <- document_term_matrix(dtm)
  dtm <- dtm_remove_lowfreq(dtm, minfreq = 5)
  termcorrelations <- dtm_cor(dtm)
  y <- as_cooccurrence(termcorrelations)
  y <- subset(y, term1 < term2 & abs(cooc) > 0.2)
  y <- y[order(abs(y$cooc), decreasing = TRUE), ]
  print(y[1:25,])
}


Corrs(x_odd.before)
Corrs(x_even.after)

home

LS0tCnRpdGxlOiAiRXh0cmVtKGlzdCkgRmlnaHRpbicgV29yZHMiCmF1dGhvcjogIkJyZWFubmEgRS4gR3JlZW4iCnN1YnRpdGxlOiBwcmFjdGljaW5nCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdGhlbWU6IHVuaXRlZAogICAgdG9jOiB5ZXMKLS0tCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQoKIyMgbG9hZCBsaWJyYXJpZXMKCmBgYHtyIGxvYWQgbGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJ30KCiMjIyBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdWRwaXBlL3ZpZ25ldHRlcy91ZHBpcGUtdXNlY2FzZS1wb3N0YWdnaW5nLWxlbW1hdGlzYXRpb24uaHRtbApsaWJyYXJ5KHVkcGlwZSkKdWRfbW9kZWwgPC0gdWRwaXBlX2Rvd25sb2FkX21vZGVsKGxhbmd1YWdlID0gImVuZ2xpc2giKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KHF1YW50ZWRhKQpsaWJyYXJ5KGxhdHRpY2UpCmxpYnJhcnkobGF0dGljZUV4dHJhKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShwZHApCmxpYnJhcnkocGF0Y2h3b3JrKQoKYGBgCgojIyBsb2FkIHRoZSBGVyBmdW5jdGlvbnMKCmBgYHtyIGxvYWRfZndfZnVuY3Rpb25zfQoKIyMjIENPREUgRElSRUNUTFkgRlJPTTogaHR0cHM6Ly9idXJ0bW9ucm9lLmdpdGh1Yi5pby9UZXh0QXNEYXRhQ291cnNlL1R1dG9yaWFscy9UQURBLUZpZ2h0aW5Xb3Jkcy5uYi5odG1sIwpmd2dyb3VwcyA8LSBmdW5jdGlvbihkdG0sIGdyb3VwcywgcGFpciA9IE5VTEwsIHdlaWdodHMgPSByZXAoMSxucm93KGR0bSkpLCBrLnByaW9yID0gLjEpIHsKICAKICB3ZWlnaHRzW2lzLm5hKHdlaWdodHMpXSA8LSAwCiAgCiAgd2VpZ2h0cyA8LSB3ZWlnaHRzL21lYW4od2VpZ2h0cykKICAKICB6ZXJvLmRvYyA8LSByb3dTdW1zKGR0bSk9PTAgfCB3ZWlnaHRzPT0wCiAgemVyby50ZXJtIDwtIGNvbFN1bXMoZHRtWyF6ZXJvLmRvYyxdKT09MAogIAogIGR0bS5ueiA8LSBhcHBseShkdG1bIXplcm8uZG9jLCF6ZXJvLnRlcm1dLDIsIioiLCB3ZWlnaHRzWyF6ZXJvLmRvY10pCiAgCiAgZy5wcmlvciA8LSB0Y3Jvc3Nwcm9kKHJvd1N1bXMoZHRtLm56KSxjb2xTdW1zKGR0bS5ueikpL3N1bShkdG0ubnopCiAgCiAgIyAKICAKICBnLnBvc3RlcmlvciA8LSBhcy5tYXRyaXgoZHRtLm56ICsgay5wcmlvcipnLnByaW9yKQogIAogIGdyb3VwcyA8LSBncm91cHNbIXplcm8uZG9jXQogIGdyb3VwcyA8LSBkcm9wbGV2ZWxzKGdyb3VwcykKICAKICBnLmFkdG0gPC0gYXMubWF0cml4KGFnZ3JlZ2F0ZSh4PWcucG9zdGVyaW9yLGJ5PWxpc3QoZ3JvdXBzPWdyb3VwcyksRlVOPXN1bSlbLC0xXSkKICByb3duYW1lcyhnLmFkdG0pIDwtIGxldmVscyhncm91cHMpCiAgCiAgZy5sYWR0bSA8LSBsb2coZy5hZHRtKQogIAogIGcuZGVsdGEgPC0gdChzY2FsZSggdChzY2FsZShnLmxhZHRtLCBjZW50ZXI9VCwgc2NhbGU9RikpLCBjZW50ZXI9VCwgc2NhbGU9RikpCiAgCiAgZy5hZHRtX3cgPC0gLXN3ZWVwKGcuYWR0bSwxLHJvd1N1bXMoZy5hZHRtKSkgIyB0ZXJtcyBub3QgdyBzcG9rZW4gYnkgawogIGcuYWR0bV9rIDwtIC1zd2VlcChnLmFkdG0sMixjb2xTdW1zKGcuYWR0bSkpICMgdyBzcG9rZW4gYnkgZ3JvdXBzIG90aGVyIHRoYW4gawogIGcuYWR0bV9rdyA8LSBzdW0oZy5hZHRtKSAtIGcuYWR0bV93IC0gZy5hZHRtX2sgLSBnLmFkdG0gIyB0b3RhbCB0ZXJtcyBub3QgdyBvciBrIAogIAogIGcuc2UgPC0gc3FydCgxL2cuYWR0bSArIDEvZy5hZHRtX3cgKyAxL2cuYWR0bV9rICsgMS9nLmFkdG1fa3cpCiAgCiAgZy56ZXRhIDwtIGcuZGVsdGEvZy5zZQogIAogIGcuY291bnRzIDwtIGFzLm1hdHJpeChhZ2dyZWdhdGUoeD1kdG0ubnosIGJ5ID0gbGlzdChncm91cHM9Z3JvdXBzKSwgRlVOPXN1bSlbLC0xXSkKICAKICBpZiAoIWlzLm51bGwocGFpcikpIHsKICAgIHByLmRlbHRhIDwtIHQoc2NhbGUoIHQoc2NhbGUoZy5sYWR0bVtwYWlyLF0sIGNlbnRlciA9IFQsIHNjYWxlID1GKSksIGNlbnRlcj1ULCBzY2FsZT1GKSkKICAgIHByLmFkdG1fdyA8LSAtc3dlZXAoZy5hZHRtW3BhaXIsXSwxLHJvd1N1bXMoZy5hZHRtW3BhaXIsXSkpCiAgICBwci5hZHRtX2sgPC0gLXN3ZWVwKGcuYWR0bVtwYWlyLF0sMixjb2xTdW1zKGcuYWR0bVtwYWlyLF0pKSAjIHcgc3Bva2VuIGJ5IGdyb3VwcyBvdGhlciB0aGFuIGsKICAgIHByLmFkdG1fa3cgPC0gc3VtKGcuYWR0bVtwYWlyLF0pIC0gcHIuYWR0bV93IC0gcHIuYWR0bV9rIC0gZy5hZHRtW3BhaXIsXSAjIHRvdGFsIHRlcm1zIG5vdCB3IG9yIGsKICAgIHByLnNlIDwtIHNxcnQoMS9nLmFkdG1bcGFpcixdICsgMS9wci5hZHRtX3cgKyAxL3ByLmFkdG1fayArIDEvcHIuYWR0bV9rdykKICAgIHByLnpldGEgPC0gcHIuZGVsdGEvcHIuc2UKICAgIAogICAgcmV0dXJuKGxpc3QoemV0YT1wci56ZXRhWzEsXSwgZGVsdGE9cHIuZGVsdGFbMSxdLHNlPXByLnNlWzEsXSwgY291bnRzID0gY29sU3VtcyhkdG0ubnopLCBhY291bnRzID0gY29sU3VtcyhnLmFkdG0pKSkKICB9IGVsc2UgewogICAgcmV0dXJuKGxpc3QoemV0YT1nLnpldGEsZGVsdGE9Zy5kZWx0YSxzZT1nLnNlLGNvdW50cz1nLmNvdW50cyxhY291bnRzPWcuYWR0bSkpCiAgfQp9CgojIyMjIyMjIyMjIyMjIyBGSUdIVElOJyBXT1JEUyBQTE9UVElORyBGVU5DVElPTgoKIyBoZWxwZXIgZnVuY3Rpb24KbWFrZVRyYW5zcGFyZW50PC1mdW5jdGlvbihzb21lQ29sb3IsIGFscGhhPTEwMCkKewogIG5ld0NvbG9yPC1jb2wycmdiKHNvbWVDb2xvcikKICBhcHBseShuZXdDb2xvciwgMiwgZnVuY3Rpb24oY3VyY29sZGF0YSl7cmdiKHJlZD1jdXJjb2xkYXRhWzFdLCBncmVlbj1jdXJjb2xkYXRhWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmx1ZT1jdXJjb2xkYXRhWzNdLGFscGhhPWFscGhhLCBtYXhDb2xvclZhbHVlPTI1NSl9KQp9Cgpmdy5nZ3Bsb3QuZ3JvdXBzIDwtIGZ1bmN0aW9uKGZ3LmNoLCBncm91cHMudXNlID0gYXMuZmFjdG9yKHJvd25hbWVzKGZ3LmNoJHpldGEpKSwgbWF4LndvcmRzID0gNTAsIG1heC5jb3VudHJhbmsgPSA0MDAsIGNvbG9ycGFsZXR0ZT1yZXAoImJsYWNrIixsZW5ndGgoZ3JvdXBzLnVzZSkpLCBzaXplc2NhbGU9MiwgdGl0bGU9IkNvbXBhcmlzb24gb2YgVGVybXMgYnkgR3JvdXBzIiwgc3VidGl0bGUgPSAiIiwgY2FwdGlvbiA9ICJHcm91cC1zcGVjaWZpYyB0ZXJtcyBhcmUgb3JkZXJlZCBieSBGaWdodGluJyBXb3JkcyBzdGF0aXN0aWMgKE1vbnJvZSwgZXQgYWwuIDIwMDgpIikgewogIGlmIChpcy5udWxsKGRpbShmdy5jaCR6ZXRhKSkpIHsjIyB0d28tZ3JvdXAgZncgb2JqZWN0IGNvbnNpc3RzIG9mIHZlY3RvcnMsIG5vdCBtYXRyaWNlcwogICAgemV0YXJhbmttYXQgPC0gY2JpbmQocmFuaygtZncuY2gkemV0YSkscmFuayhmdy5jaCR6ZXRhKSkKICAgIGNvbG5hbWVzKHpldGFyYW5rbWF0KSA8LSBncm91cHMudXNlCiAgICBjb3VudHJhbmsgPC0gcmFuaygtKGZ3LmNoJGNvdW50cykpCiAgfSBlbHNlIHsKICAgIHpldGFyYW5rbWF0IDwtIGFwcGx5KC1mdy5jaCR6ZXRhW2dyb3Vwcy51c2UsXSwxLHJhbmspCiAgICBjb3VudHJhbmsgPC0gcmFuaygtY29sU3Vtcyhmdy5jaCRjb3VudHMpKQogIH0KICB3aWRlcGxvdG1hdCA8LSBhc190aWJibGUoY2JpbmQoemV0YXJhbmttYXQsY291bnRyYW5rPWNvdW50cmFuaykpCiAgd2lkZXBsb3RtYXQkdGVybT1uYW1lcyhjb3VudHJhbmspCiAgI3JhbmtwbG90IDwtIGdhdGhlcih3aWRlcGxvdG1hdCwgcGFydHksIHpldGFyYW5rLCAxOm5jb2woemV0YXJhbmttYXQpKQogIHJhbmtwbG90IDwtIGdhdGhlcih3aWRlcGxvdG1hdCwgZ3JvdXBzLnVzZSwgemV0YXJhbmssIDE6bmNvbCh6ZXRhcmFua21hdCkpCiAgcmFua3Bsb3QkcGxvdHNpemUgPC0gc2l6ZXNjYWxlKig1MC8ocmFua3Bsb3QkemV0YXJhbmspKV4oMS80KQogIHJhbmtwbG90IDwtIHJhbmtwbG90W3JhbmtwbG90JHpldGFyYW5rIDwgbWF4LndvcmRzICsgMSAmIHJhbmtwbG90JGNvdW50cmFuazxtYXguY291bnRyYW5rKzEsXQogIHJhbmtwbG90JGdyb3Vwcy51c2UgPC0gZmFjdG9yKHJhbmtwbG90JGdyb3Vwcy51c2UsbGV2ZWxzPWdyb3Vwcy51c2UpCiAgCiAgcCA8LSBnZ3Bsb3QocmFua3Bsb3QsIGFlcygobnJvdyhyYW5rcGxvdCktY291bnRyYW5rKV4xLCAtKHpldGFyYW5rXjEpLCBjb2xvdXI9Z3JvdXBzLnVzZSkpICsgCiAgICBnZW9tX3BvaW50KHNob3cubGVnZW5kPUYsc2l6ZT1zaXplc2NhbGUvMikgKyAKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSApICsKICAgIHlsaW0oLW1heC53b3Jkcyw0MCkgKwogICAgZmFjZXRfZ3JpZChncm91cHMudXNlIH4gLikgKwogICAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IHRlcm0pLCBzaXplID0gcmFua3Bsb3QkcGxvdHNpemUsIHBvaW50LnBhZGRpbmc9LjA1LAogICAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gdW5pdCgwLjIwLCAibGluZXMiKSwgc2hvdy5sZWdlbmQ9RikgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBhbHBoYShjb2xvcnBhbGV0dGUsIC43KSkgKyAKIyAgICBsYWJzKHg9IlRlcm1zIHVzZWQgbW9yZSBmcmVxdWVudGx5IG92ZXJhbGwg4oaSIiwgeT0iVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgYnkgZ3JvdXAg4oaSIiwgIHRpdGxlPXRpdGxlLCBzdWJ0aXRsZT1zdWJ0aXRsZSAsIGNhcHRpb24gPSBjYXB0aW9uKSAKICAgIGxhYnMoeD1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgb3ZlcmFsbCAtLT4iKSwgeT1wYXN0ZSgiVGVybXMgdXNlZCBtb3JlIGZyZXF1ZW50bHkgYnkgZ3JvdXAgLS0+IiksICB0aXRsZT10aXRsZSwgc3VidGl0bGU9c3VidGl0bGUgLCBjYXB0aW9uID0gY2FwdGlvbikgCiAgCn0KCmZ3LmtleXMgPC0gZnVuY3Rpb24oZncuY2gsbi5rZXlzPTEwKSB7CiAgbi5ncm91cHMgPC0gbnJvdyhmdy5jaCR6ZXRhKQogIGtleXMgPC0gbWF0cml4KCIiLG4ua2V5cyxuLmdyb3VwcykKICBjb2xuYW1lcyhrZXlzKSA8LSByb3duYW1lcyhmdy5jaCR6ZXRhKQogIAogIGZvciAoZyBpbiAxOm4uZ3JvdXBzKSB7CiAgICBrZXlzWyxnXSA8LSBuYW1lcyhzb3J0KGZ3LmNoJHpldGFbZyxdLGRlYz1UKVsxOm4ua2V5c10pCiAgfQogIGtleXMKfQpgYGAKCgojIyBDb21wYXJlIE5ZVCAxOTk0LTIwMTA6IEJlZm9yZSBhbmQgQWZ0ZXIgImV4dHJlbWlzdCIKCipMb2FkIGFuZCBjbGVhbiB0aGUgZGF0YSoKCiAgKiB0byBzdHJpbmcgJiBsb3dlciB0ZXh0CiAgKiBwaXZvdCB0byBsb25nIGZvcm1hdAogICogYXBwbHkgdGV4dF9jbGVhbmVyIHRvIG9uZSBjb2x1bW4gImNvbnRleHQudGV4dCIKCmBgYHtyfQoKdGV4dF9jbGVhbmVyPC1mdW5jdGlvbihjb3JwdXMpewogIHRlbXBjb3JwdXM8LUNvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICByZW1vdmVQdW5jdHVhdGlvbikKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICBzdHJpcFdoaXRlc3BhY2UpCiAgdGVtcGNvcnB1czwtdG1fbWFwKHRlbXBjb3JwdXMsCiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlTnVtYmVycykKICB0ZW1wY29ycHVzPC10bV9tYXAodGVtcGNvcnB1cywKICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQogIHRlbXBjb3JwdXM8LXRtX21hcCh0ZW1wY29ycHVzLCAKICAgICAgICAgICAgICAgICAgICBzdGVtRG9jdW1lbnQpCiAgcmV0dXJuKHRlbXBjb3JwdXMpCn0KCmBgYAoKYGBge3IgY2xlYW5fdGV4dCwgZWNobz1GQUxTRSwgcmVzdWx0cz0gRkFMU0V9CgpleHRyZW1fTllULmRmbSA8LSByZWFkLmRlbGltKCJleHRyZW1pc3RfOTQxMF9OWVQudHh0IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0IikKZXh0cmVtX05ZVC5kZm0kcHViZGF0ZSA9IHN1YnN0cihleHRyZW1fTllULmRmbSRUZXh0LklELDksMTYpCmV4dHJlbV9OWVQuZGZtJHB1YmRhdGUgPC0gYXMuUE9TSVhjdChleHRyZW1fTllULmRmbSRwdWJkYXRlLCBmb3JtYXQgPSAiJVklbSVkIikKCgojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYmVmb3JlLCB0b1N0cmluZykKIyBleHRyZW1fTllULmRmbSRDb250ZXh0LmJlZm9yZSA9IGxhcHBseShleHRyZW1fTllULmRmbSRDb250ZXh0LmJlZm9yZSwgdG9sb3dlcikKIyAKIyBleHRyZW1fTllULmRmbSRDb250ZXh0LmFmdGVyID0gbGFwcGx5KGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIsIHRvU3RyaW5nKQojIGV4dHJlbV9OWVQuZGZtJENvbnRleHQuYWZ0ZXIgPSBsYXBwbHkoZXh0cmVtX05ZVC5kZm0kQ29udGV4dC5hZnRlciwgdG9sb3dlcikKCmV4dHJlbV9OWVQuZGZtIDwtIGV4dHJlbV9OWVQuZGZtICU+JSBkaXN0aW5jdChDb250ZXh0LmJlZm9yZSwgLmtlZXBfYWxsID0gVFJVRSkKCmV4dHJlbV9OWVQuZGZtLmxvbmcgPC0gcGl2b3RfbG9uZ2VyKGV4dHJlbV9OWVQuZGZtLCBjb2xzPWMoQ29udGV4dC5iZWZvcmUsIENvbnRleHQuYWZ0ZXIpLCBuYW1lc190byA9ICJDb250ZXh0IiwgdmFsdWVzX3RvID0gImNvbnRleHQudGV4dCIpCgpleHRyZW1fTllULmRmbS5sb25nJENvbnRleHQgPC0gYXMuZmFjdG9yKGV4dHJlbV9OWVQuZGZtLmxvbmckQ29udGV4dCkKCmV4dHJlbWVjb3JwdXMgPC10ZXh0X2NsZWFuZXIoZXh0cmVtX05ZVC5kZm0ubG9uZyRjb250ZXh0LnRleHQpCgpgYGAKCgpDYWxjdWxhdGUgRlcuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KCmUgPC0gZGZtKGV4dHJlbWVjb3JwdXMkY29udGVudCkKbWVzc2FnZShkaW0oZSkpCgpleHRyZW1fZHRtIDwtIGNvbnZlcnQoZSwgdG89J2RhdGEuZnJhbWUnKQpleHRyZW1fZHRtIDwtIGV4dHJlbV9kdG1bLWMoMSldCncgPC0gd2hpY2goIHNhcHBseShleHRyZW1fZHRtLCBjbGFzcyApID09ICdjaGFyYWN0ZXInICkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZncuZXh0cmVtIDwtIGZ3Z3JvdXBzKGV4dHJlbV9kdG0sIGdyb3Vwcz1leHRyZW1fTllULmRmbS5sb25nJENvbnRleHQpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCnJtKGV4dHJlbV9kdG0pCnJtKGUpCgpgYGAKCgpHZXQgYW5kIHNob3cgdGhlIHRvcCB3b3JkcyBwZXIgZ3JvdXAgYnkgemV0YS4KCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0iYXNpcyJ9Cgpmd2tleXMuZXh0cmVtIDwtIGZ3LmtleXMoZncuZXh0cmVtLCBuLmtleXM9MjApCmNvbHMgPC0gcmV2KGNvbG5hbWVzKGZ3a2V5cy5leHRyZW0pKQpmd2tleXMuZXh0cmVtIDwtIGZ3a2V5cy5leHRyZW1bLGNvbHNdCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmthYmxlKGZ3a2V5cy5leHRyZW0pCgpgYGAKClBsb3Q6IEJlZm9yZSBpbiBCbHVlLCBBZnRlciBpbiBSZWQKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD00fQoKcC5mdy5leHRyZW0gPC0gZncuZ2dwbG90Lmdyb3Vwcyhmdy5leHRyZW0sc2l6ZXNjYWxlPTQsbWF4LndvcmRzPTIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXguY291bnRyYW5rPTQwMCxjb2xvcnBhbGV0dGU9YygicmVkIiwiYmx1ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICdDb21wYXJpc29uIG9mIFRlcm1zIEJlZm9yZSBhbmQgQWZ0ZXIgIkV4dHJlbWlzdCInKQpwLmZ3LmV4dHJlbQoKYGBgCgojIyBDYWxjdWxhdGUgUGFydHMgb2Ygc3BlZWNoIGJ5IGJlZm9yZSBhbmQgYWZ0ZXIKCipDYWxjdWxhdGUgRlcgYW5kIGtleXMqCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9Cgp1ZF9tb2RlbCA8LSB1ZHBpcGVfbG9hZF9tb2RlbCh1ZF9tb2RlbCRmaWxlX21vZGVsKQoKdHh0IDwtYXMuY2hhcmFjdGVyKGV4dHJlbV9OWVQuZGZtLmxvbmckY29udGV4dC50ZXh0KQoKeF91ZHAgPC0gdWRwaXBlX2Fubm90YXRlKHVkX21vZGVsLCB4ID0gdHh0LCBkb2NfaWQgPSBzZXFfYWxvbmcodHh0KSkKeCA8LSBhcy5kYXRhLmZyYW1lKHhfdWRwKQoKeCRkb2NfaWQgPC1hcy5pbnRlZ2VyKHgkZG9jX2lkKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgp4X29kZC5iZWZvcmUgPC0geFt4JGRvY19pZCAlJSAyID09IDEsXQp4X2V2ZW4uYWZ0ZXIgPC14W3gkZG9jX2lkICUlIDIgPT0gMCwgXQoKYGBgCgoKCmBgYHtyIGJhcmNoYXJ0ZnVuY3RzLCBlY2hvPUZBTFNFfQoKIyMgVU5JVkVSU0FMIFBvUwpVUE9TX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBzdGF0czEgPC0gdHh0X2ZyZXEoZGYxJHVwb3MpCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleSwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXkpKQogIAogIHN0YXRzMiA8LSB0eHRfZnJlcShkZjIkdXBvcykKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleSkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gc3RhdHMxLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgbWFpbiA9ICJVUE9TIChVbml2ZXJzYWwgUGFydHMgb2YgU3BlZWNoKVxuIGZyZXF1ZW5jeSBvZiBvY2N1cnJlbmNlOiBCRUZPUkUgdnMgQUZURVIiLCAKICAgICAgICAgeGxhYiA9ICJGcmVxIiksIAogICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IHN0YXRzMiwgY29sID0gICdza3libHVlJywKICAgICAgICAgeGxhYiA9ICJGcmVxIikpCgp9CgoKIyMgTk9VTlMKTk9VTlNfYmFyY2hhcnQgPC0gZnVuY3Rpb24oZGYxLCBkZjIpewogIAogIHN0YXRzMSA8LSBzdWJzZXQoZGYxLCB1cG9zICVpbiUgYygiTk9VTiIpKSAKICBzdGF0czEgPC0gdHh0X2ZyZXEoc3RhdHMxJHRva2VuKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXksIGxldmVscyA9IHJldihzdGF0czEka2V5KSkKICAKICBzdGF0czIgPC0gc3Vic2V0KGRmMiwgdXBvcyAlaW4lIGMoIk5PVU4iKSkgCiAgc3RhdHMyIDwtIHR4dF9mcmVxKHN0YXRzMiR0b2tlbikKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5LCBsZXZlbHMgPSByZXYoc3RhdHMyJGtleSkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czEsIDIwKSwgY29sID0gImNhZGV0Ymx1ZSIsIAogICAgICAgICAgIG1haW4gPSAiTW9zdCBvY2N1cnJpbmcgbm91bnM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcSIpLAogICAgICBiYXJjaGFydChrZXkgfiBmcmVxLCBkYXRhID0gaGVhZChzdGF0czIsIDIwKSwgY29sID0gInNreWJsdWUiLCAKICAgICAgICAgICAgeGxhYiA9ICJGcmVxIikpCn0KCiMjIEFESkVDVElWRVMKQURKX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBzdGF0czEgPC0gc3Vic2V0KGRmMSwgdXBvcyAlaW4lIGMoIkFESiIpKSAKICBzdGF0czEgPC0gdHh0X2ZyZXEoc3RhdHMxJHRva2VuKQogIHN0YXRzMSRrZXkgPC0gZmFjdG9yKHN0YXRzMSRrZXksIGxldmVscyA9IHJldihzdGF0czEka2V5KSkKICAKICBzdGF0czIgPC0gc3Vic2V0KGRmMiwgdXBvcyAlaW4lIGMoIkFESiIpKSAKICBzdGF0czIgPC0gdHh0X2ZyZXEoc3RhdHMyJHRva2VuKQogIHN0YXRzMiRrZXkgPC0gZmFjdG9yKHN0YXRzMiRrZXksIGxldmVscyA9IHJldihzdGF0czIka2V5KSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJNb3N0IG9jY3VycmluZyBhZGplY3RpdmVzOiBCRUZPUkUgdnMgQUZURVIiLCB4bGFiID0gIkZyZXEiKSwKICAgICAgYmFyY2hhcnQoa2V5IH4gZnJlcSwgZGF0YSA9IGhlYWQoc3RhdHMyLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgIHhsYWIgPSAiRnJlcSIpKQp9CgojIyBVc2luZyBSQUtFIHRvIGZpbmQga2V5d29yZHMKUkFLRV9LV19iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsZGYyKXsKICAKICBzdGF0czEgPC0ga2V5d29yZHNfcmFrZSh4ID0gZGYxLCB0ZXJtID0gImxlbW1hIiwgZ3JvdXAgPSAiZG9jX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZWxldmFudCA9IGRmMSR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBzdGF0czIgPC0ga2V5d29yZHNfcmFrZSh4ID0gZGYyLCB0ZXJtID0gImxlbW1hIiwgZ3JvdXAgPSAiZG9jX2lkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZWxldmFudCA9IGRmMiR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICAKICBjKGJhcmNoYXJ0KGtleSB+IHJha2UsIGRhdGEgPSBoZWFkKHN1YnNldChzdGF0czEsIGZyZXEgPiAzKSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyBpZGVudGlmaWVkIGJ5IFJBS0U6IEJFRk9SRSB2cyBBRlRFUiIsIAogICAgICAgICAgIHhsYWIgPSAiUmFrZSIpLAogICAgYmFyY2hhcnQoa2V5IH4gcmFrZSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMiwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgeGxhYiA9ICJSYWtlIikpCn0KCiMjIFVzaW5nIFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24gQ29sbG9jYXRpb25zClBXSV9iYXJjaGFydCA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgZGYxJHdvcmQgPC0gdG9sb3dlcihkZjEkdG9rZW4pCiAgc3RhdHMxIDwtIGtleXdvcmRzX2NvbGxvY2F0aW9uKHggPSBkZjEsIHRlcm0gPSAid29yZCIsIGdyb3VwID0gImRvY19pZCIpCiAgc3RhdHMxJGtleSA8LSBmYWN0b3Ioc3RhdHMxJGtleXdvcmQsIGxldmVscyA9IHJldihzdGF0czEka2V5d29yZCkpCiAgCiAgZGYyJHdvcmQgPC0gdG9sb3dlcihkZjIkdG9rZW4pCiAgc3RhdHMyIDwtIGtleXdvcmRzX2NvbGxvY2F0aW9uKHggPSBkZjIsIHRlcm0gPSAid29yZCIsIGdyb3VwID0gImRvY19pZCIpCiAgc3RhdHMyJGtleSA8LSBmYWN0b3Ioc3RhdHMyJGtleXdvcmQsIGxldmVscyA9IHJldihzdGF0czIka2V5d29yZCkpCiAgCiAgYyhiYXJjaGFydChrZXkgfiBwbWksIGRhdGEgPSBoZWFkKHN1YnNldChzdGF0czEsIGZyZXEgPiAzKSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyBpZGVudGlmaWVkIGJ5IFBNSSBDb2xsb2NhdGlvbjogQkVGT1JFIHZzIEFGVEVSIiwgCiAgICAgICAgICAgeGxhYiA9ICJQTUkgKFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24pIiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IHBtaSwgZGF0YSA9IGhlYWQoc3Vic2V0KHN0YXRzMiwgZnJlcSA+IDMpLCAyMCksIGNvbCA9ICJza3libHVlIiwgCiAgICAgICAgICAgeGxhYiA9ICJQTUkgKFBvaW50d2lzZSBNdXR1YWwgSW5mb3JtYXRpb24pIikpCn0KCiMjIFVzaW5nIGEgc2VxdWVuY2Ugb2YgUE9TIHRhZ3MgKG5vdW4gcGhyYXNlcyAvIHZlcmIgcGhyYXNlcykKUE9TX2JhcmNoYXJ0IDwtIGZ1bmN0aW9uKGRmMSwgZGYyKXsKICAKICBkZjEkcGhyYXNlX3RhZyA8LSBhc19waHJhc2VtYWNoaW5lKGRmMSR1cG9zLCB0eXBlID0gInVwb3MiKQogIHN0YXRzMSA8LSBrZXl3b3Jkc19waHJhc2VzKHggPSBkZjEkcGhyYXNlX3RhZywgdGVybSA9IHRvbG93ZXIoZGYxJHRva2VuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIihBfE4pKk4oUCtEKihBfE4pKk4pKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfcmVnZXggPSBUUlVFLCBkZXRhaWxlZCA9IEZBTFNFKQogIHN0YXRzMSA8LSBzdWJzZXQoc3RhdHMxLCBuZ3JhbSA+IDEgJiBmcmVxID4gMykKICBzdGF0czEka2V5IDwtIGZhY3RvcihzdGF0czEka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMSRrZXl3b3JkKSkKICAKICBkZjIkcGhyYXNlX3RhZyA8LSBhc19waHJhc2VtYWNoaW5lKGRmMiR1cG9zLCB0eXBlID0gInVwb3MiKQogIHN0YXRzMiA8LSBrZXl3b3Jkc19waHJhc2VzKHggPSBkZjIkcGhyYXNlX3RhZywgdGVybSA9IHRvbG93ZXIoZGYyJHRva2VuKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIihBfE4pKk4oUCtEKihBfE4pKk4pKiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfcmVnZXggPSBUUlVFLCBkZXRhaWxlZCA9IEZBTFNFKQogIHN0YXRzMiA8LSBzdWJzZXQoc3RhdHMyLCBuZ3JhbSA+IDEgJiBmcmVxID4gMykKICBzdGF0czIka2V5IDwtIGZhY3RvcihzdGF0czIka2V5d29yZCwgbGV2ZWxzID0gcmV2KHN0YXRzMiRrZXl3b3JkKSkKICAKICBjKGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMSwgMjApLCBjb2wgPSAiY2FkZXRibHVlIiwgCiAgICAgICAgICAgbWFpbiA9ICJLZXl3b3JkcyAtIHNpbXBsZSBub3VuIHBocmFzZXM6IEJFRk9SRSB2cyBBRlRFUiIsIHhsYWIgPSAiRnJlcXVlbmN5IiksCiAgICAgIGJhcmNoYXJ0KGtleSB+IGZyZXEsIGRhdGEgPSBoZWFkKHN0YXRzMiwgMjApLCBjb2wgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICAgICB4bGFiID0gIkZyZXF1ZW5jeSIpKQp9CmBgYAoKCiMjIEJhciBDaGFydHMgZnJvbSBGdW5jdGlvbnMgQWJvdmUKCmBgYHtyIFBPU2JhcmNoYXJ0cywgZWNobz1UUlVFLCBmaWcud2lkdGg9OH0KClVQT1NfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpCk5PVU5TX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQpBREpfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpClJBS0VfS1dfYmFyY2hhcnQoeF9vZGQuYmVmb3JlLCB4X2V2ZW4uYWZ0ZXIpClBXSV9iYXJjaGFydCh4X29kZC5iZWZvcmUsIHhfZXZlbi5hZnRlcikKUE9TX2JhcmNoYXJ0KHhfb2RkLmJlZm9yZSwgeF9ldmVuLmFmdGVyKQoKCmBgYAoKCiMjIENvb2NjdXJlbmNlcwoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy53aWR0aD04fQoKQ09fT0Nfbm91bl9hZGpfc2FtZV9zZW50LmJlZm9yZSA8LSBmdW5jdGlvbihkZjEpewogIAogIGxpYnJhcnkoaWdyYXBoKQogIGxpYnJhcnkoZ2dyYXBoKQogIGxpYnJhcnkoZ2dwbG90MikKICAKICBjb29jIDwtIGNvb2NjdXJyZW5jZSh4ID0gc3Vic2V0KGRmMSwgdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIikpLCAKICAgICAgICAgICAgICAgICAgICAgICB0ZXJtID0gImxlbW1hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBjKCJkb2NfaWQiLCAicGFyYWdyYXBoX2lkIiwgInNlbnRlbmNlX2lkIikpCgogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIAogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJwaW5rIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrZ3JlZW4iLCBzaXplID0gNCkgKwogICAgdGhlbWVfZ3JhcGgoYmFzZV9mYW1pbHkgPSAiQXJpYWwgTmFycm93IikgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBsYWJzKHRpdGxlID0gIkNvb2NjdXJyZW5jZXMgd2l0aGluIHNlbnRlbmNlOiBCRUZPUkUiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCiAgCn0KCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5hZnRlciA8LSBmdW5jdGlvbihkZjIpewogIAogIGxpYnJhcnkoaWdyYXBoKQogIGxpYnJhcnkoZ2dyYXBoKQogIGxpYnJhcnkoZ2dwbG90MikKICAKICBjb29jIDwtIGNvb2NjdXJyZW5jZSh4ID0gc3Vic2V0KGRmMiwgdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIikpLCAKICAgICAgICAgICAgICAgICAgICAgICB0ZXJtID0gImxlbW1hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBjKCJkb2NfaWQiLCAicGFyYWdyYXBoX2lkIiwgInNlbnRlbmNlX2lkIikpCgogIHdvcmRuZXR3b3JrIDwtIGhlYWQoY29vYywgNjApCiAgd29yZG5ldHdvcmsgPC0gZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKHdvcmRuZXR3b3JrKQogIAogIGdncmFwaCh3b3JkbmV0d29yaywgbGF5b3V0ID0gImZyIikgKwogICAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gY29vYywgZWRnZV9hbHBoYSA9IGNvb2MpLCBlZGdlX2NvbG91ciA9ICJsaWdodGdyZWVuIikgKwogICAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIGNvbCA9ICJkYXJrYmx1ZSIsIHNpemUgPSA0KSArCiAgICB0aGVtZV9ncmFwaChiYXNlX2ZhbWlseSA9ICJBcmlhbCBOYXJyb3ciKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnModGl0bGUgPSAiQ29vY2N1cnJlbmNlcyB3aXRoaW4gc2VudGVuY2U6IEFGVEVSIiwgc3VidGl0bGUgPSAiTm91bnMgJiBBZGplY3RpdmUiKQogIAp9CgoKQ09fT0Nfbm91bl9hZGpfc2FtZV9zZW50LmJlZm9yZSh4X29kZC5iZWZvcmUpCkNPX09DX25vdW5fYWRqX3NhbWVfc2VudC5hZnRlcih4X2V2ZW4uYWZ0ZXIpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYmVmb3JlIDwtIGZ1bmN0aW9uKGRmKXsKICBjb29jIDwtIGNvb2NjdXJyZW5jZShkZiRsZW1tYSwgcmVsZXZhbnQgPSBkZiR1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSwgc2tpcGdyYW0gPSAxKQogIGhlYWQoY29vYykKICAKICB3b3JkbmV0d29yayA8LSBoZWFkKGNvb2MsIDYwKQogIHdvcmRuZXR3b3JrIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSh3b3JkbmV0d29yaykKICBnZ3JhcGgod29yZG5ldHdvcmssIGxheW91dCA9ICJmciIpICsKICAgIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IGNvb2MsIGVkZ2VfYWxwaGEgPSBjb29jKSwgZWRnZV9jb2xvdXIgPSAibGlnaHRncmVlbiIpICsKICAgIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCBjb2wgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIGxhYnModGl0bGUgPSAiV29yZHMgZm9sbG93aW5nIG9uZSBhbm90aGVyOiBCRUZPUkUiLCBzdWJ0aXRsZSA9ICJOb3VucyAmIEFkamVjdGl2ZSIpCn0KCkNPX09DX25vdW5fYWRqX2ZvbGxvd2luZy5hZnRlciA8LSBmdW5jdGlvbihkZil7CiAgY29vYyA8LSBjb29jY3VycmVuY2UoZGYkbGVtbWEsIHJlbGV2YW50ID0gZGYkdXBvcyAlaW4lIGMoIk5PVU4iLCAiQURKIiksIHNraXBncmFtID0gMSkKICBoZWFkKGNvb2MpCiAgCiAgd29yZG5ldHdvcmsgPC0gaGVhZChjb29jLCA2MCkKICB3b3JkbmV0d29yayA8LSBncmFwaF9mcm9tX2RhdGFfZnJhbWUod29yZG5ldHdvcmspCiAgZ2dyYXBoKHdvcmRuZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSBjb29jLCBlZGdlX2FscGhhID0gY29vYyksIGVkZ2VfY29sb3VyID0gInNreWJsdWUiKSArCiAgICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgY29sID0gImRhcmtibHVlIiwgc2l6ZSA9IDQpICsKICAgIHRoZW1lX2dyYXBoKGJhc2VfZmFtaWx5ID0gIkFyaWFsIE5hcnJvdyIpICsKICAgIGxhYnModGl0bGUgPSAiV29yZHMgZm9sbG93aW5nIG9uZSBhbm90aGVyOiBBRlRFUiIsIHN1YnRpdGxlID0gIk5vdW5zICYgQWRqZWN0aXZlIikKfQoKCkNPX09DX25vdW5fYWRqX2ZvbGxvd2luZy5iZWZvcmUoeF9vZGQuYmVmb3JlKQpDT19PQ19ub3VuX2Fkal9mb2xsb3dpbmcuYWZ0ZXIoeF9ldmVuLmFmdGVyKQoKYGBgCgoKCiMjIENvb2NjdXJlbmNlcyAocGFydCAyKQoKYGBge3J9CgoKQ29ycnMgPC0gZnVuY3Rpb24oZGYpewogIGRmJGlkIDwtIHVuaXF1ZV9pZGVudGlmaWVyKGRmLCBmaWVsZHMgPSBjKCJzZW50ZW5jZV9pZCIsICJkb2NfaWQiKSkKICBkdG0gPC0gc3Vic2V0KGRmLCB1cG9zICVpbiUgYygiTk9VTiIsICJBREoiKSkKICBkdG0gPC0gZG9jdW1lbnRfdGVybV9mcmVxdWVuY2llcyhkdG0sIGRvY3VtZW50ID0gImlkIiwgdGVybSA9ICJsZW1tYSIpCiAgZHRtIDwtIGRvY3VtZW50X3Rlcm1fbWF0cml4KGR0bSkKICBkdG0gPC0gZHRtX3JlbW92ZV9sb3dmcmVxKGR0bSwgbWluZnJlcSA9IDUpCiAgdGVybWNvcnJlbGF0aW9ucyA8LSBkdG1fY29yKGR0bSkKICB5IDwtIGFzX2Nvb2NjdXJyZW5jZSh0ZXJtY29ycmVsYXRpb25zKQogIHkgPC0gc3Vic2V0KHksIHRlcm0xIDwgdGVybTIgJiBhYnMoY29vYykgPiAwLjIpCiAgeSA8LSB5W29yZGVyKGFicyh5JGNvb2MpLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KICBwcmludCh5WzE6MjUsXSkKfQoKCkNvcnJzKHhfb2RkLmJlZm9yZSkKQ29ycnMoeF9ldmVuLmFmdGVyKQpgYGAKCmBgYHtyIGZpbmFsfQpgYGAKCgoKCgoKCgpbaG9tZV0oaHR0cHM6Ly9icmVncmVlbi5naXRodWIuaW8vKQo=